<?php

declare(strict_types=1);
/**
 * 
 */
namespace WanZ\App\User\Logic;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Context\Context;
use Hyperf\Redis\RedisFactory;
use WanZ\App\User\Contract\WzUserAttributeContract;
use WanZ\App\User\Consumer\Order;
use WanZ\App\User\Logic\CompanyLogic;
use WanZ\App\User\Logic\UserBlackLogic;
use WanZ\App\User\Logic\WxLogic;
use WanZ\App\User\Logic\Traits\UserTrait;
use WanZ\App\User\Logic\Traits\SmsTrait;
use WanZ\App\Utils\JwtBuilder;  
use WanZ\App\Utils\Prometheus\PrometheusFactory;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;

/**
 * 用户管理.
 *
 * Class UserLogic
 */
class UserLogic
{
    use UserTrait;
    use SmsTrait;

    /**
     * @Inject
     * @var CompanyLogic
     */
    private $companyLogic;   

    /**
     * @Inject
     * @var UserBlackLogic
     */
    private $userBlackLogic;

    /**
     * @Inject
     * @var WxLogic
     */
    private $wxLogic;  
    
    /**
     * @Inject
     * @var AliLogic
     */
    private $aliLogic;

    /**
     * @Inject
     * @var JwtBuilder
     */
    private $jwtBuilder;
    
    /**
     * @Inject
     * @var StdoutLoggerInterface
     */
    private $logger;


    /**
     * 充电用户登录
     *
     * @param string $loginType
     * @param string $authCode
     * @param int $companyId
     * @return array
     * @throws CommonException
     */
	public function login(string $loginType, string $authCode, int $companyId) : array
	{
        $cache = make(RedisFactory::class)->get('default');
		$key = sprintf('cache:login:%s', $authCode);
		$data = json_decode((string) $cache->get($key), true);
		if (!empty($data)) {
			return $data;
		}
        
        $user = [];
		if ($loginType == 'wx') {
			$user = $this->wxLogic->login($authCode, $companyId);
		} elseif ($loginType == 'ali') {
			$user = $this->aliLogic->login($authCode, $companyId);
		} else {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '非法登录方式');
        }

        $activeKey = sprintf('data:active:%d:%s:%s', $companyId, $loginType, date('Ymd'));
        $activeUserKey = sprintf('active:%d:%s:%s:%d', $companyId, $loginType, date('Ymd'), $user['id']);

        if (! $cache->exists($activeUserKey)) {
            $tomorrow = strtotime(date('Y-m-d', strtotime('+1 day')));
            $cache->setex($activeUserKey, $tomorrow - time(), date('Y-m-d H:i:s'));
            $cache->incr($activeKey);
            $cache->expire($activeKey, 86400 * 3);
        }

        try {
            $userPhone = $this->getUserBaseInfoByUserId((int) $user['userId'], ['phone', 'user_id']);
            $user['phone'] = $userPhone['phone'] ?? '';
        } catch (\Throwable $e) {
            $user['phone'] = '';
        }

		return $this->loginReturn($user, $companyId, $key);
	}

   /**
     *
     * @param array $user
     * @param int $companyId
     * @param string $key
     * @return array
     * @throws CommonException
     */
	private function loginReturn(array $user = [], int $companyId = 0, string $key = ''): array
	{
		$data = [];

		if (empty($user)) {
			$data['is_bind_phone'] = false;
			return $data;
		}

		$data['u_id'] = $user['id'];
		$data['is_bind_phone'] = !empty($user['phone']);
		$data['company_id'] = $companyId;

		// 返回JWT的TOKEN
		$data += $this->jwtBuilder->genUserToken($companyId, (int) $user['id'], 1);
        $cache = make(RedisFactory::class)->get('default');
		if (!empty($key)) {
			$cache->set($key, json_encode($data, JSON_UNESCAPED_UNICODE));
			$cache->expire($key, 600);
		}
		// 更新时间最后登录时间
        make(WzUserAttributeContract::class)->updateUserAttrByUserId((int) $user['id'], ['updated_at' => date('Y-m-d H:i:s')]);

		return $data;
	} 

    /**
     * @param int $userId
     * @param int $companyId
     * @param int $isHiddenPhone
     * @param int $groupId
     * @return array 响应数组
     */
    public function getUserInfoById(int $userId = 0, int $companyId = 0, int $isHiddenPhone = 0, int $groupId = 0): array
    {
        try {
            $data = $this->getUserInfo($userId);
            $data['balance'] = $data['wxBalance'] + $data['aliBalance'];
        
            $company = $this->companyLogic->getById($companyId);
            $data['company']['qrcode'] = $company['qrcode'];
            $data['equity'] = 0;
            $data['OfficialLink'] = config('common.OfficialLink.' . $companyId, '');
            
            list($limitCharge, $limitPowerFigure) = $this->userBlackLogic->checkIsBlackByUserPhone($data['phone']);
            $data['isBlack'] = (int) $limitCharge;
            $data['isLimitPowerFigure'] = (int) $limitPowerFigure;

            $data['isOpenWxPayScore'] = $this->isOpenWxPayScoreByUserPhone($data['phone']);

            $data['isOpenDiscountCoin'] = $data['discountCoinBalance'] = $data['discountCoinNum'] = 0;
            if ($groupId > 0) {
                $disCountCoinRes = make(Order::class)->_([
                    'company_id' => $companyId, 'u_id' => $userId, 'u_type' => 1, 'group_id' => $groupId
                    ])->getDisCountCoinByUserId();
                    
                $data['isOpenDiscountCoin'] = $disCountCoinRes['isOpenDiscountCoin'];
                $data['discountCoinBalance'] = $disCountCoinRes['discountCoinBalance'];
                $data['discountCoinNum'] = $disCountCoinRes['discountCoinNum'];
            }

            list($agreementId, $state) = $this->getAliCreditCreditAgreementIdByPhone($data['phone']);
            $data['creditAgreementId'] = $agreementId;
            $data['aliCreditState'] = $state;

            $data['isOpenDigitalRmb'] = (int) $this->isOpenDigitalRmb($data['phone']);

            if ($isHiddenPhone === 1) {
                $data['phone'] = hiddenPhone($data['phone']);
            }

            return $data;
        } catch (\Throwable $exception) {
            $this->logger->error('getClientUserInfoErrorRes', [
                'requestData' => $userId,
                'company_id' => $companyId,
                'errorMsg' => $exception->getMessage(),
                'site' => $exception->getFile().$exception->getLine(),
                'traceid' => Context::get('traceid', ''),
                'client_tranceid' => Context::get('client_traceid', ''),
            ]);

            PrometheusFactory::user()->addErrorNumToGetUserInfo($userId);
            throw $exception;
        }            
    }


    /**
     * 绑定（更新）手机号
     * @param string $phone
     * @param string $code
     * @param int $userId
     * @param string $type
     * @return bool
     */
	public function bind(string $phone = '', string $code = '', int $userId = 0, string $type = ''): bool
	{
        try {
            $check = $this->verifyCodeHandle($phone, 'reset_wx_account', $code);
            // 验证手机号验证码
            if (!$check) {
                throw new CommonException(ErrorCode::INVALID_PARAMS, '短信验证码已经过期');
            }

            return $this->updateUserPhone($userId, $phone, $type);
        } catch (\Throwable $e) {
            $this->logger->error(sprintf('%s [%s] %s', '验证手机号验证码失败', date('Y-m-d H:i:s'), $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
            throw new CommonException(ErrorCode::SERVER_ERROR, '验证手机号验证码失败');          
        }

        return true;
    }

}
